# AUTHOR: DING
# -*- codeing = utf-8 -*-
# @Time: 2024/2/1 17:11
# @Author: 86139
# @Site: 
# @File: 03-gradDescnt.py
# @Software: PyCharm

# 线性回归，梯度下降
import numpy as np
import random
import torch
import time


def compute_error_for_line_given_points(b, w, points):
    # 计算损失值
    totalError = 0
    for i in range(0, len(points)):
        x = points[i, 0]
        y = points[i, 1]
        totalError += (y - (w * x + b)) ** 2
    return totalError / float(len(points))


def step_gradient(b_current, w_current, points, learning_rate):
    # 梯度下降
    b_gradient = 0
    w_gradient = 0
    N = float(len(points))
    for i in range(0, len(points)):
        x = points[i, 0]
        y = points[i, 1]
        b_gradient += -(2 / N) * (y - (w_current * x + b_current))
        w_gradient += -(2 / N) * x * (y - (w_current * x + b_current))
    new_b = b_current - learning_rate * b_gradient
    new_w = w_current - learning_rate * w_gradient
    return [new_b, new_w]


def gradient_descent_runner(points, starting_b, starting_w, learing_rate, num_iterations):
    # 开始求解
    b = starting_b
    w = starting_w
    for i in range(num_iterations):
        b, w = step_gradient(b, w, np.array(points), learing_rate)
    return [b, w]


def run():
    points = []
    for i in range(150):
        x = i
        y = 2 * x + 3 + random.uniform(-0.05, 0.05)
        points.append([x, y])
    points = np.array(points)
    learning_rate = 0.0001
    initial_b = 0
    initial_w = 0
    num_iter = 1000
    print("Before b ={0} w = {1} error = {2}".format(initial_b, initial_w,
                                                     compute_error_for_line_given_points(initial_b, initial_w, points)))
    [b, w] = gradient_descent_runner(points, initial_b, initial_w, learning_rate, num_iter)
    print([b, w])
    print("After b ={0} w = {1} error = {2}".format(b, w, compute_error_for_line_given_points(b, w, points)))


if __name__ == "__main__":
    run()
